package com.lxx.securitydemo2.config;

import com.lxx.securitydemo2.filter.JwtAuthenticationTokenFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableMethodSecurity
public class SecurityConfig {

    @Autowired
    public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

    @Autowired
    private AuthenticationEntryPoint authenticationEntryPoint;

    @Autowired
    private AccessDeniedHandler accessDeniedHandler;


    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    // 登录时需要调用AuthenticationManager.authenticate进行用户验证
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        http.
                // 配置请求的拦截方式
                        authorizeHttpRequests(auth -> auth
                        // permitAll：此表达式指示资源对所有用户开放，无论他们是否经过了身份验证。换句话说，它允许匿名用户和已登录用户都能够访问相关的资源。
                        // anonymous:这个表达式用于指定某个资源或服务只能被匿名用户访问，，一旦用户通过了登录认证流程(例如，用户携带有效的token信息请求资源)，该用户将不能再访问被标记为.anonymous()的资源。
                        //
                        // 对于登录接口，允许随意访问
                        .requestMatchers("/user/login").permitAll()
                        // 除上面外的所有请求需要鉴权认证
                        .anyRequest().authenticated())
                // 关闭csrf
                .csrf(AbstractHttpConfigurer::disable)
                // 前后端分离是无状态的，不需要session了，直接禁用。
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                // 添加过滤器
                .addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
                // 注入异常处理器
                .exceptionHandling(handler -> handler.accessDeniedHandler(accessDeniedHandler))
                .exceptionHandling(entryPoint -> entryPoint.authenticationEntryPoint(authenticationEntryPoint));


        return http.build();
    }

}
